

#include <cassert>
#include <iostream>
#include <vector>
using namespace std;
#include <chrono>
#include <cstdio>
void MyTimer(int type, const char *info = nullptr) {
  static std::chrono::steady_clock::time_point start;
  if (type == 0) {
    start = std::chrono::steady_clock::now();
    printf("Begin %s\n", info);
    return;
  } else {
    auto end = std::chrono::steady_clock::now();
    auto dt =
        std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
    printf("End %s, time taken=%lf\n", info, dt.count());
  }
}

// 直接使用 vector 没有任何问题  又快又好
/**  一维情况下还是 vector 快
 * @brief  g++ 使用 vector 优化后比 arr 要快
 *
 *
 *  使用point 后 也要比 array 快   数组不太容易优化
 *
 *  array 难优化  避免使用
 *
 *  结论: 使用vector 没有性能损失,开优化等级1就很棒了
 *  能使用vector 的地方就使用vector
 * @return int
 */
#define NDEBUG
using real_t = double;
struct Point {
  real_t p[3];
  real_t &operator[](int i) noexcept {
    assert(-1 < i && i < 3);
    return p[i];
  }
  const real_t &operator[](int i) const noexcept {
    assert(-1 < i && i < 3);
    return p[i];
  }
  real_t &x() noexcept { return p[0]; }
  real_t &y() noexcept { return p[1]; }
  real_t &z() noexcept { return p[2]; }
  const real_t &x() const noexcept { return p[0]; }
  const real_t &y() const noexcept { return p[1]; }
  const real_t &z() const noexcept { return p[2]; }
  real_t *data() noexcept { return p; }
  const real_t *data() const noexcept { return p; }
  int size() const noexcept { return 3; }

  Point &operator/=(const real_t val) {
    p[0] /= val;
    p[1] /= val;
    p[2] /= val;
    return *this;
  }
  Point &operator+=(const Point &varp) {
    p[0] += varp[0];
    p[1] += varp[1];
    p[2] += varp[2];
    return *this;
  }

  bool operator==(const Point &pp) const {
    return (p[0] == pp.p[0]) && (p[1] == pp.p[1]) && (p[2] == pp.p[2]);
  }
};
// 测试前后都有依赖关系的算例
void test(vector<Point> &pvec, int n) {
  pvec[0] = Point{0, 0, 0};
  for (int i = 1; i < n; ++i) {
    pvec[i].x() = pvec[i - 1].x() + 0.1;
    pvec[i].y() = pvec[i].x() + 0.2;
    pvec[i].z() = pvec[i].y() + 0.5;
  }
}

void test(Point *pvec, int n) {
  pvec[0] = Point{0, 0, 0};
  for (int i = 1; i < n; ++i) {
    // i3 = i * 3;
    // parr[i].x() = i * 0.12;
    // parr[i].y() = i * 0.22;
    // parr[i].z() = i * 0.32;
    pvec[i].x() = pvec[i - 1].x() + 0.1;
    pvec[i].y() = pvec[i].x() + 0.2;
    pvec[i].z() = pvec[i].y() + 0.5;
  }
}

bool isSame(const vector<Point> &pvec, const Point *parr) {
  const int tmp = pvec.size();
  for (int i = 0; i < tmp; ++i) {
    if (!(pvec[i] == parr[i])) {
      cout << "not same\n" << endl;
      return false;
    }
  }
  return true;
}

void test_vec(int n) {
  vector<Point> pvec(n);
  for (int i = 0; i < n; ++i) {
    pvec[i].x() = i * 0.12;
    pvec[i].y() = i * 0.22;
    pvec[i].z() = i * 0.32;
  }
}

void test_arr(int n) {
  Point *parr{new Point[n]{}};
  // for(int i = 0; i < n; ++i)
  // {
  // }
  for (int i = 0; i < n; ++i) {
    // i3 = i * 3;
    parr[i].x() = i * 0.12;
    parr[i].y() = i * 0.22;
    parr[i].z() = i * 0.32;
  }
  delete[] parr;
}

class t1 {
private:
  int n;
  vector<Point> pvec;

public:
  t1(int nn) : n{nn}, pvec(n) {}
  vector<Point> &getPvec() { return pvec; }
  void test();
};

void t1::test() {
  pvec[0] = Point{0, 0, 0};
  for (int i = 1; i < n; ++i) {

    pvec[i].x() = pvec[i - 1].x() + 0.1;
    pvec[i].y() = pvec[i].x() + 0.2;
    pvec[i].z() = pvec[i].y() + 0.5;
  }
}

class t2 {
private:
  int n;
  Point *parr;

public:
  ~t2() { delete[] parr; }
  Point *getParr() { return parr; }
  t2(int nn) : n{nn}, parr{new Point[n]} {}
  void test();
};

void t2::test() {
  parr[0] = Point{0, 0, 0};

  for (int i = 1; i < n; ++i) {
    parr[i].x() = parr[i - 1].x() + 0.1;
    parr[i].y() = parr[i].x() + 0.2;
    parr[i].z() = parr[i].y() + 0.5;
  }
}

int main(int argc, char *argv[]) {

  if (argc != 2) {
    cerr << "./a.out num_elems" << endl;
    exit(EXIT_FAILURE);
  }
  const int n = atoi(argv[1]) * 50000000;

  // int n = 100000000;
  // vector<double> vec(n);
  // double *arr = new double[n];

  // MyTimer(0, "vector");
  // for (int i = 0; i < n; ++i)
  //   vec[i] = i * 0.1;
  // MyTimer(1, " ");

  // MyTimer(0, "array");
  // for (int i = 0; i < n; ++i)
  //   arr[i] = i * 0.1;
  // MyTimer(1, " ");

  // //   arr[100] = 100;
  // MyTimer(0, "compare");
  // for (int i = 0; i < n; ++i)
  //   if (vec[i] != arr[i]) {
  //     cout << "not equal\n";
  //     exit(EXIT_FAILURE);
  //   }
  // MyTimer(1, " ");

  // vector<Point> pvec(n);
  // Point *parr = new Point[n];
  // Point *pparr = new Point[n];

  // MyTimer(0, "vector");
  // for (int i = 0; i < n; ++i) {
  //   pvec[i].x() = i * 0.1;
  //   pvec[i].y() = i * 0.2;
  //   pvec[i].z() = i * 0.3;
  // }
  // MyTimer(1, " ");

  // vector 中的元素在开始时会默认执行初始化
  // MyTimer(0, "vector int class");
  // t1 tvec(n);
  // tvec.test();
  // MyTimer(1, " ");
  // MyTimer(0, "array in class");
  // t2 tarr(n);
  // tarr.test();
  // MyTimer(1, " ");

  t1 tvec2(n + 100000);
  t2 tarr2(n + 100000);
  MyTimer(0, "array in class2");
  tarr2.test();
  MyTimer(1, " ");
  MyTimer(0, "vector int class2");
  tvec2.test();
  MyTimer(1, " ");

  // t1 tvec3(n + 1200000);
  // t2 tarr3(n + 1200000);

  // MyTimer(0, "array2");
  // test(tarr3.getParr(), n);
  // MyTimer(1, " ");
  // MyTimer(0, "vector2");
  // test(tvec3.getPvec(), n);
  // MyTimer(1, " ");

  // vector<Point> pvec(n + 1);
  // Point *parr = new Point[n + 1];
  // // vector 要快
  // MyTimer(0, "function vec");
  // test(pvec, n);
  // MyTimer(1, " ");
  // MyTimer(0, "funciton arr");
  // test(parr, n);
  // MyTimer(1, " ");

  // cout << "is same " << isSame(pvec, parr) << endl;
  // 下面两者时间相同
  // MyTimer(0, "function vec");
  // test_vec(n);
  // MyTimer(1, " ");
  // MyTimer(0, "funciton arr");
  // test_arr(n);
  // MyTimer(1, " ");

  Point *p{new Point[1]};
  cout << p->x() << "  " << p->y() << "  " << p->z() << endl;
  //   arr[100] = 100;
  // MyTimer(0, "compare");
  // for (int i = 0; i < n; ++i) {
  //   i3 = i * 3;
  //   if ((pvec[i][0] != parr[i3]) && (pvec[i][1] != parr[i3 + 1]) &&
  //       (pvec[i][2] != parr[i3 + 2])) {
  //     cout << "not equal\n";
  //     exit(EXIT_FAILURE);
  //   }
  // }
  // MyTimer(1, " ");

  // // 上下两个没有区别
  // MyTimer(0, "vector2");
  // for (int i = 0; i < n; ++i) {
  //   Point &p{pvec[i]};
  //   p.x() = i * 0.1;
  //   p.y() = i * 0.2;
  //   p.z() = i * 0.3;
  // }
  // MyTimer(1, " ");

  // MyTimer(0, "compare");
  // for (int i = 0; i < n; ++i) {
  //   i3 = i * 3;
  //   if ((pvec[i][0] != parr[i3]) && (pvec[i][1] != parr[i3 + 1]) &&
  //       (pvec[i][2] != parr[i3 + 2])) {
  //     cout << "not equal\n";
  //     exit(EXIT_FAILURE);
  //   }
  // }
  // MyTimer(1, " ");

  // pvec.resize(0);
  // MyTimer(0, "vector3 push_back");
  // Point tp;
  // for (int i = 0; i < n; ++i) {

  //   tp.x() = i * 0.1;
  //   tp.y() = i * 0.2;
  //   tp.z() = i * 0.3;
  //   pvec.emplace_back(tp);
  // }
  // MyTimer(1, " ");

  // MyTimer(0, "array point");
  // for (int i = 0; i < n; ++i) {
  //   pparr[i].x() = i * 0.1;
  //   pparr[i].y() = i * 0.2;
  //   pparr[i].z() = i * 0.3;
  //   // pvec.emplace_back(tp);
  // }
  // MyTimer(1, " ");

  // MyTimer(0, "array2");
  // for (int i = 0; i < n; ++i) {
  //   i3 = i * 3;
  //   parr[i3] = i * 0.1;
  //   parr[i3 + 1] = i * 0.2;
  //   parr[i3 + 2] = i * 0.3;
  // }
  // MyTimer(1, " ");

  // //   arr[100] = 100;
  // MyTimer(0, "compare");
  // for (int i = 0; i < n; ++i) {
  //   i3 = i * 3;
  //   if ((pvec[i][0] != parr[i3]) && (pvec[i][1] != parr[i3 + 1]) &&
  //       (pvec[i][2] != parr[i3 + 2])) {
  //     cout << "not equal\n";
  //     exit(EXIT_FAILURE);
  //   }
  // }
  // MyTimer(1, " ");

  // delete[] arr;
  // delete[] parr;
  // delete[] pparr;
  return 0;
}